package com.circle.rest.modular.qrtz.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.circle.rest.core.aop.Log;
import com.circle.rest.core.aop.Permission;
import com.circle.rest.core.common.enums.BusinessType;
import com.circle.rest.core.common.model.SuccessResponseData;
import com.circle.rest.core.common.page.PageInfoBT;
import com.circle.rest.core.exception.ServiceException;
import com.circle.rest.core.util.SchedulerUtil;
import com.circle.rest.core.util.ToolUtil;
import com.circle.rest.modular.qrtz.model.Task;
import com.circle.rest.modular.qrtz.model.TaskRecord;
import com.circle.rest.modular.qrtz.service.ITaskRecordService;
import com.circle.rest.modular.qrtz.service.ITaskService;
import com.circle.rest.modular.qrtz.wrapper.TaskRecordWrapper;
import com.circle.rest.modular.qrtz.wrapper.TaskWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 定时任务 前端控制器
 * </p>
 *
 * @author 赵航
 * @since 2019-04-12
 */
@Api(value = "定时任务", tags = {"qrtz : 定时任务API"})
@RestController
@RequestMapping("/qrtz/task")
public class TaskController {

    @Autowired
    private ITaskService taskService;


    @Autowired
    private ITaskRecordService taskRecordService;

    /**
     * 查询定时任务列表
     */
    @ApiOperation("查询定时任务列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "index", value = "起始数据下标", dataType = "int"),
            @ApiImplicitParam(name = "size", value = "数据条数", dataType = "int"),
            @ApiImplicitParam(name = "condition", value = "关键字", dataType = "String")
    })
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    @Log(title = "查询定时任务列表", businessType = BusinessType.SELECT_LIST)
    @Permission
    public Object list(Integer index, Integer size, String condition) {
        Page<Task> page = new Page<>(index == null ? 1 : index, size == null ? 15 : size);
        QueryWrapper<Task> wrapper = new QueryWrapper<>();
        IPage<Map<String, Object>> mapIPage = taskService.pageMaps(page, wrapper);
        PageInfoBT<Object> objectPageInfoBT = new PageInfoBT<>(new TaskWrapper(mapIPage).wrap());
        return new SuccessResponseData(objectPageInfoBT);
    }


    /**
     * 查询定时任务执行记录列表
     */
    @ApiOperation("查询定时任务执行记录列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "index", value = "起始数据下标", dataType = "int"),
            @ApiImplicitParam(name = "size", value = "数据条数", dataType = "int"),
            @ApiImplicitParam(name = "condition", value = "关键字", dataType = "String")
    })
    @RequestMapping(value = "/recordList", method = RequestMethod.GET)
    @Log(title = "查询定时任务执行记录列表", businessType = BusinessType.SELECT_LIST)
    @Permission
    public Object recordList(Integer index, Integer size, String condition) {
        Page<TaskRecord> page = new Page<>(index == null ? 1 : index, size == null ? 15 : size);
        QueryWrapper<TaskRecord> wrapper = new QueryWrapper<>();
        IPage<Map<String, Object>> mapIPage = taskRecordService.pageMaps(page, wrapper);
        PageInfoBT<Object> objectPageInfoBT = new PageInfoBT<>(new TaskRecordWrapper(mapIPage).wrap());
        return new SuccessResponseData(objectPageInfoBT);
    }

    /**
     * 添加定时任务
     */
    @ApiOperation("添加定时任务")
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @Log(title = "添加定时任务", businessType = BusinessType.INSERT)
    @Permission
    public Object add(Task task) throws Exception {
        if (ToolUtil.isEmpty(task.getName())) {
            throw new ServiceException("任务名称不能为空，且全局唯一");
        }
        if (ToolUtil.isEmpty(task.getJobReference())) {
            throw new ServiceException("Job引用路径不能为空");
        }

        QueryWrapper<Task> wrapper = new QueryWrapper<>();
        wrapper.eq("name", task.getName());
        List<Task> list = taskService.list(wrapper);
        if (list.size() > 0) {
            throw new ServiceException("当前任务名称已经存在");
        }

        //com.circle.rest.modular.qrtz.job.JobTest
        String jobReference = task.getJobReference();
        QuartzJobBean quartzJobBean = (QuartzJobBean) Class.forName(jobReference).newInstance();
        //TODO 目前任务执行的开始时间和结束时间写死默认便于测试
        SchedulerUtil.createSchedule(
                quartzJobBean.getClass(),
                task.getName(),
                task.getCron(),
                new Date(),
                null,
                task.getIntervalInSeconds(),
                task.getTriggerRepeatCount());
        task.setUpdateTime(LocalDateTime.now());
        task.setCreateTime(LocalDateTime.now());
        task.setStatus(Trigger.TriggerState.NORMAL.ordinal());
        task.setStartTime(new Date());
        task.setEndTime(new Date(System.currentTimeMillis() + 1000 * 120));
        boolean save = taskService.save(task);
        return new SuccessResponseData(save);
    }

    /**
     * 修改定时任务
     */
    @ApiOperation("修改定时任务")
    @RequestMapping(value = "/edit", method = RequestMethod.POST)
    @Log(title = "修改定时任务", businessType = BusinessType.UPDATE)
    @Permission
    @Transactional
    public Object edit(Task task) throws Exception {
        if (ToolUtil.isEmpty(task.getId())) {
            throw new ServiceException("编号不能为空");
        }
        if (ToolUtil.isEmpty(task.getVersion())) {
            throw new ServiceException("版本号不能为空");
        }
        task.setUpdateTime(LocalDateTime.now());
        if (!taskService.updateById(task)) {
            throw new ServiceException("更新失败(版本号不一致)");
        }

        Task oldTask = taskService.getById(task.getId());
        Trigger.TriggerState triggerState = SchedulerUtil.getTriggerState(oldTask.getName());
        if (triggerState == Trigger.TriggerState.NORMAL) {

            if (ToolUtil.isNotEmpty(task.getName()) && !task.getName().equals(oldTask.getName())) {
                throw new ServiceException("正在执行中的任务不能修改名称");
            }
            //正在执行中 修改任务参数后保存
            SchedulerUtil.editSchedule(
                    oldTask.getName(),
                    task.getCron() == null ? oldTask.getCron() : task.getCron(),
                    task.getStartTime() == null ? oldTask.getStartTime() : task.getStartTime(),
                    task.getEndTime() == null ? oldTask.getEndTime() : task.getEndTime(),
                    task.getIntervalInSeconds() == null ? oldTask.getIntervalInSeconds() : task.getIntervalInSeconds(),
                    task.getTriggerRepeatCount() == null ? oldTask.getTriggerRepeatCount() : task.getTriggerRepeatCount());
        }

        return new SuccessResponseData();
    }

    /**
     * 删除定时任务
     */
    @ApiOperation("删除定时任务")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "定时任务编号", required = true, dataType = "String")
    })
    @RequestMapping(value = "/delete", method = RequestMethod.GET)
    @Log(title = "删除定时任务", businessType = BusinessType.DELETE)
    @Permission
    public Object delete(String id) throws Exception {

        if (ToolUtil.isEmpty(id)) {
            throw new ServiceException("定时任务编号不能为空");
        }
        Task taskOld = taskService.getById(id);
        if (ToolUtil.isEmpty(taskOld)) {
            throw new ServiceException("定时任务不存在，删除失败");
        }

        Task task = taskService.getById(id);
        Trigger.TriggerState triggerState = SchedulerUtil.getTriggerState(task.getName());
        if (triggerState != Trigger.TriggerState.NONE) {
            //TODO 删除正在执行中的定时任务
            SchedulerUtil.removeSchedule(task.getName());
        }

        if (!taskService.removeById(id)) {
            throw new ServiceException("删除失败");
        }
        return new SuccessResponseData();
    }

    /**
     * 查询定时任务
     */
    @ApiOperation("查询定时任务")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "定时任务编号", required = true, dataType = "String")
    })
    @RequestMapping(value = "/detail", method = RequestMethod.GET)
    @Log(title = "查询定时任务", businessType = BusinessType.SELECT_ONE)
    @Permission
    public Object detail(String id) {
        if (ToolUtil.isEmpty(id)) {
            throw new ServiceException("定时任务编号不能为空");
        }
        Task task = taskService.getById(id);
        if (ToolUtil.isEmpty(task)) {
            throw new ServiceException("定时任务不存在");
        }
        return new SuccessResponseData(task);
    }

    /**
     * 开始/暂停 定时任务
     */
    @ApiOperation("开始/暂停 定时任务")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "定时任务编号", required = true, dataType = "String")
    })
    @RequestMapping(value = "/pause", method = RequestMethod.GET)
    @Log(title = "开始/暂停 定时任务", businessType = BusinessType.UPDATE)
    @Permission
    public Object pause(String id) throws Exception {
        if (ToolUtil.isEmpty(id)) {
            throw new ServiceException("定时任务编号不能为空");
        }
        Task task = taskService.getById(id);
        SchedulerUtil.pauseOrResumeSchedule(task.getName());

        return new SuccessResponseData();
    }
}
